#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sys/select.h>

#include "auxiliaire.h"
#include "types.h"

void resetTLB(TLB_table *tlb, int entry_num){
	int i;

	if(tlb->tbe==NULL){
		tlb->tbe = (TLB_entry*) malloc(entry_num*sizeof(TLB_entry));
		tlb->entry_num = entry_num;
	}

	tlb->entry_pointer = 0;

	for(i=0; i < tlb->entry_num; i++){
		tlb->tbe[i].frame_num = -1;
		tlb->tbe[i].page_num = -1;
	}
}

void deleteTLB(TLB_table *tlb){
	free(tlb->tbe);
	tlb->tbe = NULL;
	tlb->entry_num = 0;
}

int cadreAssocie(TLB_table tlb, int page){
	int i;

	for(i=0; i<tlb.entry_num; i++)
		if (tlb.tbe[i].page_num == page)
			return tlb.tbe[i].frame_num;

	return -1;
}

void addTLB( TLB_table *tlb, int page, int cadre){

	int pt;

	if(cadreAssocie(*tlb,page) != -1){
		int i;

		for(i=0; i < tlb->entry_num; i++)
			if (tlb->tbe[i].page_num == page){
				pt = i;
				break;
			}
	}
	else{
		pt = tlb->entry_pointer;
		(tlb->entry_pointer)++;
		(tlb->entry_pointer) %= tlb->entry_num;
	}

	tlb->tbe[pt].page_num = page;
	tlb->tbe[pt].frame_num = cadre;
}
/*Lorsque le processus OS réclame le numéro du cadre associé à la page d'indice k,le processus MMU regarde dans le TLB si une entré
 contient une page d'indice k et dans ce cas retourne la valeur du cadre associé. Si l'entrée n'existe pas, le processus MMU retourne
 à 1 au processus OS.Lorsque l'on change de processus, il faut réinitialiser le TLB. Le processus OS envoie le message « FLUSH » au
 processus MMU et ce dernier place toutes les entrées page_num du TLB à la valeur -1  */

int main(int argc, char** argv){

    int arg1, arg2;
    cmd_mmu command;
    char buffer[BUFFER_SIZE];
    int nPages, nCadres;
    TLB_table tlb;

    if(argc!= 3){
    	fprintf(stderr, "SVP, mettez comme entré le nombre de pages suivi par le nombre de cadres.");
    	exit(EXIT_FAILURE);
    }

    nPages = atoi(argv[1]);
    nCadres = atoi(argv[2]);

    tlb.tbe = NULL;
    resetTLB(&tlb,nCadres);

    while(1){

    	arg1 = -1;
    	arg2 = -1;

    	if( read_and_parse(stdin,buffer,&arg1,&arg2)<=0 ){
    	    fprintf(stderr,"<< Demande invalide >>\n");
    	    continue;
    	}
    	else{
    		command = str2cmd_mmu(buffer);
    	    if(command==INERROR){
    	        fprintf(stderr,"<< Demande invalide >>\n");
    	        continue;
    	    }
    	}

    	switch(command){
			case InPt:
				if(arg1 == -1){
					fprintf(stderr,"<< Demande invalide >>\n");
					break;
				}
				printf("%d\n",cadreAssocie(tlb,arg1));
				break;

			case InAdd:
				if (arg1==-1 || arg2 ==-1){
					fprintf(stderr,"<< Demande invalide >>\n");
					printf("-1\n");
					break;
				}
				if(arg1>=nPages || arg2>=nCadres){
					printf("-1\n");
					break;
				}
				addTLB(&tlb,arg1,arg2);
				printf("OK\n");
				break;

			case InFlush:
				resetTLB(&tlb,tlb.entry_num);
				printf("OK\n");
				break;

			case InKill_mmu :
				deleteTLB(&tlb);
			    exit(EXIT_SUCCESS);

			default : break;
        }
    }

    deleteTLB(&tlb);
    exit(EXIT_FAILURE);
}
